import json

from django.core.serializers.json import DjangoJSONEncoder
from django.http import JsonResponse
from django.shortcuts import render
from app01.models import VibrationData, BearingHealth, VibrationAudio
import joblib
import numpy as np
from scipy.stats import skew, kurtosis
import warnings
import time
# 忽略特定警告
warnings.filterwarnings("ignore", category=UserWarning, module="sklearn")

# 全局变量
# 避免每次要重新加载
model = joblib.load(r"DataFix/ML/test_code/data_set_with_audio/RandomForest/v2/vibration_model_RF_v2.pkl")


def index(request):
    """
    @fun_name: index
    @author: fei_niao
    @created: 2025-5-1
    @last_modified: 2025-5-1
    @version: 1.0.0
    @license: Apache 2.0

    Description:
        可视化轴承状况
        @parameter： request
        @return： render函数
    """
    global bearing_chart_data
    bearings = []
    chart_data = []
    timestamps = []

    try:
        # 获取四个轴承的数据（ID:0-3）
        for bearing_id in [0, 1, 2, 3]:
            # 获取指定轴承的最新数据（单条）
            bearing_data = VibrationData.objects.select_related('health_status', 'audio_data') \
                .filter(bearing_id=bearing_id) \
                .latest('timestamp')

            # 获取该轴承的图表数据（最近x条）
            bearing_chart_data = VibrationData.objects.prefetch_related('audio_data') \
                                     .filter(bearing_id=bearing_id) \
                                     .order_by('-timestamp')[:200][::-1]  # 反转顺序：旧→新

            # 如果是第一个轴承，初始化图表时间戳
            if bearing_id == 0:
                timestamps = [d.timestamp.strftime("%H:%M:%S") for d in bearing_chart_data]

            # 提取音频特征
            audio_features = getattr(bearing_data.audio_data, 'extracted_features', {})

            # 准备预测数据
            prediction_data = [
                bearing_data.x_acc_rms,
                bearing_data.y_acc_rms,
                bearing_data.z_acc_rms,
                bearing_data.x_v_rms,
                bearing_data.y_v_rms,
                bearing_data.z_v_rms,
                *list(audio_features.values())
            ]

            # 执行预测
            prediction_result = predict_sample(prediction_data)

            # 构造轴承数据
            bearings.append({
                'id': bearing_id,
                'acceleration': {
                    'x': bearing_data.x_acc_rms,
                    'y': bearing_data.y_acc_rms,
                    'z': bearing_data.z_acc_rms
                },
                'velocity': {
                    'x': bearing_data.x_v_rms,
                    'y': bearing_data.y_v_rms,
                    'z': bearing_data.z_v_rms
                },
                'temperature': bearing_data.temperature,
                'audio_features': audio_features,
                'prediction': prediction_result,
                'chart_data': list(bearing_chart_data),  # 每个轴承数据
            })

    except VibrationData.DoesNotExist:
        pass

    return render(request, 'index.html', {
        'bearings': bearings,
        'timestamps': timestamps  # 时间戳（以bearing_id=0的为准）
    })


def test_page(requests):
    """
    @fun_name: test_page
    @author: fei_niao
    @created: 2025-4-29
    @last_modified: 2025-4-30
    @version: 1.0.0
    @license: Apache 2.0

    Description:
        可视化页面效果测试页
        @parameter： request
        @return： render函数
    """
    return render(requests, 'test_page.html')


# 工具函数，解析音频数据，返回11特征，服务于index
def extract_time_features(audio_data):
    """
    @fun_name: extract_time_features
    @author: fei_niao
    @created: 2025-4-29
    @last_modified: 2025-4-30
    @version: 1.0.0
    @license: Apache 2.0

    Description:
        提取音频的11核心特征
        @parameter： audio_data 列表
        @return： features 字典
    """
    features = {
        'mean': float(np.mean(audio_data)),
        'std': float(np.std(audio_data)),
        'max': float(np.max(audio_data)),
        'min': float(np.min(audio_data)),
        'peak_to_peak': float(np.ptp(audio_data)),
        'rms': float(np.sqrt(np.mean(np.square(audio_data)))),
        'mean_abs': float(np.mean(np.abs(audio_data))),
        'skewness': float(skew(audio_data)),
        'kurtosis': float(kurtosis(audio_data)),
        'energy': float(np.sum(np.square(audio_data))),
        'entropy': float(-np.sum(np.square(audio_data) * np.log(np.square(audio_data) + 1e-10)))
    }
    # print(features)
    return features


# 工具函数，调用RF模型预测样本，服务于index
def predict_sample(sample):
    """
    @fun_name: predict_sample
    @author: fei_niao
    @created: 2025-4-29
    @last_modified: 2025-4-30
    @version: 1.0.0
    @license: Apache 2.0

    Description:
        调用训练好的模型进行预测
        @parameter： 样本列表
        @return： features 字典
    """
    try:
        # 记录开始时间
        start_time = time.time()
        # 1. 加载预存资源
        # 全局变量已加载
        # 2. 数据预处理
        sample_array = np.array(sample).reshape(1, -1)  # 转换为二维数组

        # 3. 执行预测
        probability = model.predict_proba(sample_array)  # 获取概率
        prediction = model.predict(sample_array)  # 获取分类结果

        print("对轴承最新数据故障概率预测结果：")

        print(f"{probability}")

        # 计算耗时（毫秒）
        elapsed_time = (time.time() - start_time) * 1000

        # print(f"模型预测耗时：{elapsed_time} ms")

        # 4. 结果解释
        return {
            "normal_probability": probability[0][0],
            "abnormal_probability": probability[0][1],
            "prediction": int(prediction[0])
        }
    except Exception as e:
        print(f"预测失败：{str(e)}")
        return {
            "normal_probability": 0.9,
            "abnormal_probability": 0.1,
            "prediction": 0
        }


def get_bearing_data(request):
    """API接口：返回轴承数据的JSON"""
    bearings = []
    try:
        for bearing_id in [0, 1, 2, 3]:
            # 获取最新数据
            bearing_data = VibrationData.objects.select_related('health_status', 'audio_data') \
                .filter(bearing_id=bearing_id) \
                .latest('timestamp')

            # 获取图表数据（最近200条）
            chart_data = VibrationData.objects.filter(bearing_id=bearing_id) \
                             .order_by('-timestamp')[:200][::-1]

            # 处理音频特征
            audio_features = getattr(bearing_data.audio_data, 'extracted_features', {})

            # 准备预测数据
            prediction_data = [
                bearing_data.x_acc_rms,
                bearing_data.y_acc_rms,
                bearing_data.z_acc_rms,
                bearing_data.x_v_rms,
                bearing_data.y_v_rms,
                bearing_data.z_v_rms,
                *list(audio_features.values())
            ]

            # 执行预测
            prediction_result = predict_sample(prediction_data)

            bearings.append({
                'id': bearing_id,
                'acceleration': {
                    'x': bearing_data.x_acc_rms,
                    'y': bearing_data.y_acc_rms,
                    'z': bearing_data.z_acc_rms
                },
                'velocity': {
                    'x': bearing_data.x_v_rms,
                    'y': bearing_data.y_v_rms,
                    'z': bearing_data.z_v_rms
                },
                'temperature': bearing_data.temperature,
                'audio_features': audio_features,
                'prediction': prediction_result,
                'chart_data': [
                    {
                        'timestamp': d.timestamp.strftime("%H:%M:%S"),
                        'acceleration': {
                            'x': d.x_acc_rms,
                            'y': d.y_acc_rms,
                            'z': d.z_acc_rms
                        },
                        'velocity': {
                            'x': d.x_v_rms,
                            'y': d.y_v_rms,
                            'z': d.z_v_rms
                        },
                        'temperature': d.temperature,
                        'audio_features': getattr(d.audio_data, 'extracted_features', {})
                    }
                    for d in chart_data
                ]
            })

    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)

    return JsonResponse({'bearings': bearings}, encoder=DjangoJSONEncoder)


# import json
# import time
# import numpy as np
# import joblib
# from scipy.stats import skew, kurtosis
# import warnings
# from django.http import JsonResponse
# from django.shortcuts import render
# from django.core.serializers.json import DjangoJSONEncoder
# from app01.models import VibrationData, BearingHealth, VibrationAudio
#
# # 忽略特定警告
# warnings.filterwarnings("ignore", category=UserWarning, module="sklearn")
#
# # 全局模型变量
# model = joblib.load(r"DataFix/ML/test_code/data_set_with_audio/RandomForest/v2/vibration_model_RF_v2.pkl")
#
#
# def serialize_vibration_data(data):
#     """将VibrationData对象序列化为字典"""
#     return {
#         'timestamp': data.timestamp.strftime("%H:%M:%S"),
#         'x_acc_rms': data.x_acc_rms,
#         'y_acc_rms': data.y_acc_rms,
#         'z_acc_rms': data.z_acc_rms,
#         'x_v_rms': data.x_v_rms,
#         'y_v_rms': data.y_v_rms,
#         'z_v_rms': data.z_v_rms,
#         'temperature': data.temperature,
#         'audio_data': {
#             'extracted_features': getattr(data.audio_data, 'extracted_features', {})
#         } if hasattr(data, 'audio_data') else {}
#     }
#
#
# def index(request):
#     """
#     主页面视图：初始化轴承监测数据
#     """
#     bearings = []
#     timestamps = []
#
#     try:
#         # 获取四个轴承的数据（ID:0-3）
#         for bearing_id in [0, 1, 2, 3]:
#             # 获取指定轴承的最新数据
#             bearing_data = VibrationData.objects.select_related('health_status', 'audio_data') \
#                 .filter(bearing_id=bearing_id) \
#                 .latest('timestamp')
#
#             # 获取该轴承的图表数据（最近200条）
#             bearing_chart_data = VibrationData.objects.prefetch_related('audio_data') \
#                                      .filter(bearing_id=bearing_id) \
#                                      .order_by('-timestamp')[:200][::-1]
#
#             # 初始化时间戳（以第一个轴承为准）
#             if bearing_id == 0:
#                 timestamps = [d.timestamp.strftime("%H:%M:%S") for d in bearing_chart_data]
#
#             # 提取音频特征
#             audio_features = getattr(bearing_data.audio_data, 'extracted_features', {})
#
#             # 准备预测数据并执行预测
#             prediction_result = predict_sample([
#                 bearing_data.x_acc_rms,
#                 bearing_data.y_acc_rms,
#                 bearing_data.z_acc_rms,
#                 bearing_data.x_v_rms,
#                 bearing_data.y_v_rms,
#                 bearing_data.z_v_rms,
#                 *list(audio_features.values())
#             ])
#
#             # 构造轴承数据
#             bearings.append({
#                 'id': bearing_id,
#                 'acceleration': {
#                     'x': bearing_data.x_acc_rms,
#                     'y': bearing_data.y_acc_rms,
#                     'z': bearing_data.z_acc_rms
#                 },
#                 'velocity': {
#                     'x': bearing_data.x_v_rms,
#                     'y': bearing_data.y_v_rms,
#                     'z': bearing_data.z_v_rms
#                 },
#                 'temperature': bearing_data.temperature,
#                 'audio_features': audio_features,
#                 'prediction': prediction_result,
#                 'chart_data': [serialize_vibration_data(d) for d in bearing_chart_data],
#             })
#
#     except VibrationData.DoesNotExist:
#         pass
#
#     # 将数据序列化为JSON用于前端初始化
#     bearings_json = json.dumps(bearings, cls=DjangoJSONEncoder)
#
#     return render(request, 'index.html', {
#         'bearings': bearings,
#         'timestamps': timestamps,
#         'bearings_json': bearings_json
#     })
#
#
# def get_bearing_data(request):
#     """
#     AJAX API接口：返回轴承数据的JSON格式
#     """
#     bearings = []
#     try:
#         for bearing_id in [0, 1, 2, 3]:
#             # 获取最新数据
#             bearing_data = VibrationData.objects.select_related('health_status', 'audio_data') \
#                 .filter(bearing_id=bearing_id) \
#                 .latest('timestamp')
#
#             # 获取图表数据（最近200条）
#             chart_data = VibrationData.objects.filter(bearing_id=bearing_id) \
#                              .order_by('-timestamp')[:200][::-1]
#
#             # 处理音频特征
#             audio_features = getattr(bearing_data.audio_data, 'extracted_features', {})
#
#             # 执行预测
#             prediction_result = predict_sample([
#                 bearing_data.x_acc_rms,
#                 bearing_data.y_acc_rms,
#                 bearing_data.z_acc_rms,
#                 bearing_data.x_v_rms,
#                 bearing_data.y_v_rms,
#                 bearing_data.z_v_rms,
#                 *list(audio_features.values())
#             ])
#
#             bearings.append({
#                 'id': bearing_id,
#                 'acceleration': {
#                     'x': bearing_data.x_acc_rms,
#                     'y': bearing_data.y_acc_rms,
#                     'z': bearing_data.z_acc_rms
#                 },
#                 'velocity': {
#                     'x': bearing_data.x_v_rms,
#                     'y': bearing_data.y_v_rms,
#                     'z': bearing_data.z_v_rms
#                 },
#                 'temperature': bearing_data.temperature,
#                 'audio_features': audio_features,
#                 'prediction': prediction_result,
#                 'chart_data': [serialize_vibration_data(d) for d in chart_data]
#             })
#
#     except Exception as e:
#         return JsonResponse({'error': str(e)}, status=500)
#
#     return JsonResponse({'bearings': bearings}, encoder=DjangoJSONEncoder)
#
#
# def predict_sample(sample):
#     """
#     工具函数：调用训练好的模型进行预测
#     """
#     try:
#         sample_array = np.array(sample).reshape(1, -1)
#         probability = model.predict_proba(sample_array)
#         prediction = model.predict(sample_array)
#
#         return {
#             "normal_probability": probability[0][0],
#             "abnormal_probability": probability[0][1],
#             "prediction": int(prediction[0])
#         }
#     except Exception as e:
#         print(f"预测失败：{str(e)}")
#         return {
#             "normal_probability": 0.9,
#             "abnormal_probability": 0.1,
#             "prediction": 0
#         }
#
#
# def extract_time_features(audio_data):
#     """
#     工具函数：提取音频的11个核心特征
#     """
#     return {
#         'mean': float(np.mean(audio_data)),
#         'std': float(np.std(audio_data)),
#         'max': float(np.max(audio_data)),
#         'min': float(np.min(audio_data)),
#         'peak_to_peak': float(np.ptp(audio_data)),
#         'rms': float(np.sqrt(np.mean(np.square(audio_data)))),
#         'mean_abs': float(np.mean(np.abs(audio_data))),
#         'skewness': float(skew(audio_data)),
#         'kurtosis': float(kurtosis(audio_data)),
#         'energy': float(np.sum(np.square(audio_data))),
#         'entropy': float(-np.sum(np.square(audio_data) * np.log(np.square(audio_data) + 1e-10)))
#     }
#
#
# def test_page(request):
#     """
#     测试页面视图
#     """
#     return render(request, 'test_page.html')